﻿using System;

namespace Tool.PEMath
{
    public struct PEInt
    {
        public long ScaledValue { get; set; }

        private const int BIT_MOVE_COUNT = 10;
        private const long MULTIPLIER_FACTOR = 1 << BIT_MOVE_COUNT;
        
        
        public static readonly PEInt zero = new PEInt(0);
        public static readonly PEInt one = new PEInt(1);
        public static readonly PEInt pi = new PEInt(3.1416f);
        
        
        #region 构造函数

        private PEInt(long scaledValue)
        {
            ScaledValue = scaledValue;
        }
        public PEInt(int val)
        {
            ScaledValue = val * MULTIPLIER_FACTOR;
        }
        
        public PEInt(float val)
        {
            ScaledValue = (long)Math.Round(val * MULTIPLIER_FACTOR);
        }

        public static implicit operator PEInt(Int32 i) => new PEInt(i);
        public static explicit operator PEInt(float f) => new PEInt((long)Math.Round(f * MULTIPLIER_FACTOR));
        #endregion

        #region 运算符
        public static PEInt operator +(PEInt a, PEInt b) => new PEInt(a.ScaledValue + b.ScaledValue);
        public static PEInt operator -(PEInt a, PEInt b) => new PEInt(a.ScaledValue - b.ScaledValue);
        public static PEInt operator *(PEInt a, PEInt b) 
        {
            long value = a.ScaledValue * b.ScaledValue; 
            if(value >= 0) 
                value >>= BIT_MOVE_COUNT;
            else 
                value = -(-value >> BIT_MOVE_COUNT);
            return new PEInt(value);
        }

        public static PEInt operator /(PEInt a, PEInt b) => b.ScaledValue == 0 ? throw new Exception()
            : new PEInt((a.ScaledValue << BIT_MOVE_COUNT) / b.ScaledValue);
        public static PEInt operator -(PEInt value) => new PEInt(-value.ScaledValue);
        
        public static bool operator ==(PEInt a, PEInt b) => a.ScaledValue == b.ScaledValue;
        public static bool operator !=(PEInt a, PEInt b) => a.ScaledValue != b.ScaledValue;
        public static bool operator >(PEInt a, PEInt b) => a.ScaledValue > b.ScaledValue;
        public static bool operator <(PEInt a, PEInt b) => a.ScaledValue < b.ScaledValue;
        public static bool operator >=(PEInt a, PEInt b) => a.ScaledValue >= b.ScaledValue;
        public static bool operator <=(PEInt a, PEInt b) => a.ScaledValue <= b.ScaledValue;
        public static PEInt operator <<(PEInt value, int moveCount) => new PEInt(value.ScaledValue << moveCount);
        public static PEInt operator >>(PEInt value, int moveCount) 
        {
            if(value.ScaledValue >= 0) 
                return new PEInt(value.ScaledValue >> moveCount);
            else
                return new PEInt(-(-value.ScaledValue >> moveCount));
        }
        /*public static PEInt operator >>(PEInt value, int moveCount) =>
            new PEInt(value.ScaleValue >= 0?value.ScaleValue >> moveCount:-(-value.ScaleValue >> moveCount));*/
        #endregion

        /**
         * 返回float值，不可再用于逻辑运算,只能用于表现层
         */
        public float RawFloat => ScaledValue * 1.0f / MULTIPLIER_FACTOR;
        
        /**
         * 返回int值，不可再用于逻辑运算,只能用于表现层
         */
        public int RawInt 
        {
            get 
            {
                if(ScaledValue >= 0) 
                    return (int)(ScaledValue >> BIT_MOVE_COUNT);
                else 
                    return -(int)(-ScaledValue >> BIT_MOVE_COUNT);
            }
        }

        public override bool Equals(object obj)
        {
            if(obj == null) 
                return false;
            var peInt = (PEInt)obj;
            return ScaledValue == peInt.ScaledValue;
        }
        
        public override int GetHashCode()
        {
            return ScaledValue.GetHashCode();
        }

        public override string ToString()
        {
            return RawFloat.ToString();
        }
    }
    
    
}
